﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using CultuRAM.DAL;
using CultuRAM.Models;
using PagedList;

namespace CultuRAM.Controllers
{
    [Authorize]
    public class StatisticsController : Controller
    {

        private readonly UnitOfWork _unitOfWork = new UnitOfWork();
        //private static int _idParam, _page;
        private static string _msgInfo, _msgSuccess, _msgWarning, _msgError;

        //
        // GET: /Statistics/

        public ActionResult Index()
        {
            PopulateGroupFieldDropDownList();
            PopulateEventTypeDropDownList();
            PopulateEntityDropDownList();
            PopulateEntityTypeDropDownList();
            PopulateStatesDropDownList();
            PopulatePlacesDropDownList();
            PopulateCitiesDropDownList();
            PopulateParticipDropDownList();
            PopulateParticipTypeDropDownList();

            ViewBag.DateStart = new DateTime(DateTime.Now.Year, 1, 1).ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
            ViewBag.DateEnd = new DateTime(DateTime.Now.Year, 12, 31).ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);

            ViewBag.FilterList = new SelectList(new[]
                {
                    new SelectListItem {Value = "0", Text = "Sem filtros selecionados..."}
                }, "Value", "Text").OrderBy(x => x.Value);

            return View();
        }

        //
        // GET: /Parameters/StaticDate

        public ActionResult StaticDate(string stringFilter, int id = 0, int page = 0)
        {
            ViewBag.MsgSuccess = _msgSuccess;
            ViewBag.MsgError = _msgError;
            ViewBag.MsgWarning = _msgWarning;
            ViewBag.MsgInfo = _msgInfo;
            _msgSuccess = String.Empty;
            _msgError = String.Empty;
            _msgInfo = String.Empty;
            _msgWarning = String.Empty;

            var strFilter = stringFilter.Split(new string[] { "," }, StringSplitOptions.None);
            var ddlGroupField = strFilter[0];        
            int groupField = ddlGroupField != null ? Convert.ToInt32(ddlGroupField) : 0;
            
            var result = BuildStatisticList(stringFilter, page);

            ViewBag.stFilter = stringFilter;

            return groupField == 0 ? PartialView("_DefaultData") : PartialView("_StaticData", result);
        }

        
        //AUXILIARY METHODS /////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////

        //Method: Build Statistical Data List
        private IPagedList<Statistic> BuildStatisticList(string stringFilter, int page = 0)
        {

            var strFilter = stringFilter.Split(new string[] { "," }, StringSplitOptions.None);

            var ddlGroupField = strFilter[0];
            var ddlEntity = strFilter[1];
            var ddlState = strFilter[2];
            var ddlPlace = strFilter[3];
            var ddlCity = strFilter[4];
            var ddlParticip = strFilter[5];
            var ddlType = strFilter[6];
            var ddlEntityType = strFilter[7];
            var ddlParticipantType = strFilter[8];
            var txtDateStart1 = strFilter[9];
            var txtDateEnd1 = strFilter[10] + " 23:59:59";

            var txtDateStart = "01-01-2015 00:00:00";
            var txtDateEnd = "31-12-2015 23:59:59";

            var  filterList = new List<SelectListItem>{};

            for (var i = 1; i < strFilter.Length - 2; i++)
            {
                if (!String.IsNullOrEmpty(strFilter[i]))
                {
                    filterList.Add(new SelectListItem {Value = i.ToString(CultureInfo.InvariantCulture), Text = strFilter[i]});
                }
            }
            

            ViewBag.FilterList = new SelectList(new[]
                {
                    filterList
                }, "Value", "Text").OrderBy(x => x.Value);


            int groupField = ddlGroupField != null ? Convert.ToInt32(ddlGroupField) : 0;

            var allPlaces = _unitOfWork.PlaceRepository.Get().ToList();

            DateTime dTxtDateStart = new DateTime(DateTime.Now.Year, 1, 1);
            DateTime dTxtDateEnd = new DateTime(DateTime.Now.Year, 12, 31);

            if (!txtDateStart.Equals(String.Empty))
                dTxtDateStart = DateTime.Parse(txtDateStart);

            if (!txtDateEnd.Equals(String.Empty))
                dTxtDateEnd = DateTime.Parse(txtDateEnd);

            
            var events = _unitOfWork.EventRepository.Get()
                                        .Where(evt => evt.StartDate >= dTxtDateStart &&
                                                      evt.StartDate <= dTxtDateEnd && 
                                                      evt.Entity.Name.Contains(ddlEntity) &&
                                                      evt.HasPropertyNullOrEqual("Estado", ddlState) &&
                                                      evt.HasPropertyNullOrEqual("Local", ddlPlace) &&
                                                      evt.HasCityValue(evt.GetCityValue(evt.GetPropertyValue("Local"), allPlaces), ddlCity) &&
                                                      evt.EventType.Type.Contains(ddlType) &&
                                                      evt.Entity.EntityType.EntityTypeName.Contains(ddlEntityType) &&
                                                      evt.HasParticipant(ddlParticip) &&
                                                      evt.HasParticipantType(ddlParticipantType) 
                                        );

            var dados = new List<Statistic>();

            int pageSize = 8;
            int pageNumber = page != 0 ? page : 1; 


            switch (groupField)
            {
                case 1: //Entity
                    var entities = _unitOfWork.EntityRepository.Get();

                    dados.AddRange(
                        from entity in entities
                        let qtd = events.Count(ev => entity.Name.Equals(ev.Entity.Name))
                        select new Statistic(entity.Name, qtd));

                    break;
                
                case 2: //State
                    var eventStates = _unitOfWork.EventStateRepository.Get();

                    dados.AddRange(
                        from eventState in eventStates 
                        let qtd = events.Count(ev => eventState.State.Equals(ev.GetPropertyValue("Estado")))    
                        select new Statistic(eventState.State, qtd));
                    break;
                
                case 3: //Place
                    var places = _unitOfWork.PlaceRepository.Get();

                    dados.AddRange(
                        from place in places
                        let qtd = events.Count(ev => place.NamePlace.Equals(ev.GetPropertyValue("Local"))) 
                        //select new Statistic(new {DataName = place.NamePlace, DataCount = qtd}));
                        select new Statistic(place.NamePlace, qtd ));
                    break;

                case 4: //Months
                    //var entities = _unitOfWork.EntityRepository.Get();
                    string[] nM = DateTimeFormatInfo.CurrentInfo.MonthNames;
                    var monthNames = new List<string>();
                    int i = 0;
                    
                    foreach (string m in nM)
                    {
                        monthNames.Add(DateTimeFormatInfo.CurrentInfo.GetMonthName(i + 1));
                        i++;
                    }
                    monthNames.RemoveAt(12);

                    
                    dados.AddRange(
                        from mName in monthNames
                        let qtd = events.Count(ev => ev.StartDate.ToString("MMMM", CultureInfo.CurrentCulture).Equals(mName))
                        select new Statistic(mName, qtd));
                    break;

                case 5: //City
                    var placess = _unitOfWork.PlaceRepository.Get().ToList();
                    var cities = _unitOfWork.CityRepository.Get().ToList();

                    dados.AddRange(
                        from city in cities
                        let qtd = events.Count(ev => city.CityName.Equals(ev.GetCityValue(ev.GetPropertyValue("Local"), placess))) 
                        select new Statistic(city.CityName, qtd));
                    break;

                case 6: //Participant
                    var participants = _unitOfWork.ParticipantRepository.Get().ToList();
                    var eventss = _unitOfWork.EventRepository.Get().ToList();

                    var qtdInt = 0;

                    foreach (Participant p in participants)
                    {
                        qtdInt += eventss.SelectMany(ev => ev.EventParticipants).Count(ep => p.Name.Equals(ep.Participant.Name));
                        var dado = p.Name;

                        //dados.AddRange(new List<string[]> { new string[] { dado, Convert.ToString(qtdInt) } });
                        dados.AddRange(new List<Statistic> {new Statistic(dado, qtdInt)});

                        qtdInt = 0;
                        dado = String.Empty;
                    }
 
                    break;

                case 7: //Target 
                    var targets = _unitOfWork.TargetRepository.Get();

                    dados.AddRange(
                        from target in targets
                        let qtd = events.Count(ev => target.TargetName.Equals(ev.GetPropertyValue("Público-alvo")))
                        select new Statistic(target.TargetName, qtd));
                    break;
          
                case 8: //Event Type
                    var eventTypes = _unitOfWork.EventTypeRepository.Get();
                    dados.AddRange(
                        from eventType in eventTypes
                        let qtd = events.Count(ev => eventType.Type.Equals(ev.EventType.Type))
                        select new Statistic(eventType.Type, qtd));
                    break;

                case 9: //Entity Type
                    var entityTypes = _unitOfWork.EntityTypeRepository.Get();

                    dados.AddRange(
                        from entityType in entityTypes
                        let qtd = events.Count(ev => entityType.EntityTypeName.Equals(ev.Entity.EntityType.EntityTypeName))
                        select new Statistic(entityType.EntityTypeName,qtd));
                    break;

                case 10: //Participant Type
                    var participTypes = _unitOfWork.ParticipantTypeRepository.Get().ToList();
                    var eventsss = _unitOfWork.EventRepository.Get().ToList();

                    var qtdIntt = 0;

                    foreach (ParticipantType p in participTypes)
                    {
                        qtdIntt += eventsss.SelectMany(ev => ev.EventParticipants).
                                    Count(ep => p.ParticipType.Equals(ep.Participant.ParticipantType.ParticipType));
                        string dadoo = p.ParticipType;

                        dados.AddRange(new List<Statistic> { new Statistic(dadoo, qtdIntt) });

                        qtdIntt = 0;
                        dadoo = String.Empty;
                    }
         
                    break;
            }


            if (!Request.HttpMethod.Equals("GET"))
            {
                page = 1;
            }

            dados = dados.Where(d => d.DataCount != 0).OrderBy(c => c.DataName).ToList();

            //Get Chart
            ViewBag.DataChart = BuildStatisticChart(dados);
          
            return dados.ToPagedList(pageNumber, pageSize);
        }
        
        //Method: Populate the DropDownList Group Field
        private void PopulateGroupFieldDropDownList(int id = 0)
        {
            ViewBag.GroupField = new SelectList(new[]
                {
                    new SelectListItem {Value = "0", Text = ""},
                    new SelectListItem {Value = "1", Text = "Entidade"},
                    new SelectListItem {Value = "2", Text = "Estado"},
                    new SelectListItem {Value = "3", Text = "Local"},
                    new SelectListItem {Value = "4", Text = "Meses"},
                    new SelectListItem {Value = "5", Text = "Município"},
                    new SelectListItem {Value = "6", Text = "Participante"},
                    new SelectListItem {Value = "7", Text = "Público-alvo"},
                    new SelectListItem {Value = "8", Text = "Tipo de Evento"},
                    new SelectListItem {Value = "9", Text = "Tipo de Entidade"},
                    new SelectListItem {Value = "10", Text = "Tipo de Participante"}

                }, "Value", "Text", id).OrderBy(x => x.Text);
        }

        //Method: Populate the DropDownList of Participant Types
        private void PopulateParticipTypeDropDownList(int? selectedParticipTypeId = null)
        {
            if (selectedParticipTypeId == null)
            {
                var participTypes = _unitOfWork.ParticipantTypeRepository.GetList().OrderBy(p => p.ParticipType);
                ViewBag.ParticipantTypeIdSt = new SelectList(participTypes, "ParticipTypeId", "ParticipType");
            }
            else
            {
                var participTypes = _unitOfWork.ParticipantTypeRepository.GetList().OrderBy(p => p.ParticipType);
                ViewBag.ParticipantTypeIdSt = new SelectList(participTypes, "ParticipTypeId", "ParticipType", selectedParticipTypeId);
            }
        }

        //Method: Populate the DropDownList of Participants
        private void PopulateParticipDropDownList(int? selectedParticipId = null)
        {
            if (selectedParticipId == null)
            {
                var particip = _unitOfWork.ParticipantRepository.GetList().OrderBy(o => o.Name);
                ViewBag.ParticipIdSt = new SelectList(particip, "ParticipId", "Name");
            }
            else
            {
                var particip = _unitOfWork.ParticipantRepository.GetList().OrderBy(o => o.Name);
                ViewBag.ParticipIdSt = new SelectList(particip, "ParticipId", "Name", selectedParticipId);
            }
        }

        //Method: Populate the DropDownList of Event Types
        private void PopulateEventTypeDropDownList(int? selectedEventTypeId = null)
        {
            if (selectedEventTypeId == null)
            {
                var eeventTypes = _unitOfWork.EventTypeRepository.GetList().OrderBy(o => o.Type);
                ViewBag.EventTypeIdSt = new SelectList(eeventTypes, "TypeId", "Type");
            }
            else
            {
                var eeventTypes = _unitOfWork.EventTypeRepository.GetList().OrderBy(o => o.Type);
                ViewBag.EventTypeIdSt = new SelectList(eeventTypes, "TypeId", "Type", selectedEventTypeId);
            }
        }

        //Method: Populate the DropDownList of Entity Types
        private void PopulateEntityTypeDropDownList(int? selectedEntityTypeId = null)
        {
            if (selectedEntityTypeId == null)
            {
                var entityTypes = _unitOfWork.EntityTypeRepository.GetList().OrderBy(o => o.EntityTypeName);
                ViewBag.EntityTypeIdSt = new SelectList(entityTypes, "EntityTypeId", "EntityTypeName");
            }
            else
            {
                var entityTypes = _unitOfWork.EntityTypeRepository.GetList().OrderBy(o => o.EntityTypeName);
                ViewBag.EntityTypeIdSt = new SelectList(entityTypes, "EntityTypeId", "EntityTypeName", selectedEntityTypeId);
            }
        }

        //Method: Populate the DropDownList of Entities 
        private void PopulateEntityDropDownList(int? selectedEntityId = null)
        {
            if (selectedEntityId == null)
            {
                var entities = _unitOfWork.EntityRepository.GetList().OrderBy(et => et.Name);
                ViewBag.EntityIdSt = new SelectList(entities, "EntityId", "Name");
            }
            else
            {
                var entities = _unitOfWork.EntityRepository.GetList().OrderBy(et => et.Name);
                ViewBag.EntityIdSt = new SelectList(entities, "EntityId", "Name", selectedEntityId);
            }
        }
        
        //Method: Populate the DropDownList of States 
        private void PopulateStatesDropDownList(int? selectedStateId = null)
        {
            if (selectedStateId == null)
            {
                var states = _unitOfWork.EventStateRepository.GetList().OrderBy(o => o.State);
                ViewBag.StateIdSt = new SelectList(states, "StateId", "State");
            }
            else
            {
                var states = _unitOfWork.EventStateRepository.GetList().OrderBy(o => o.State);
                ViewBag.StateIdSt = new SelectList(states, "StateId", "State", selectedStateId);
            }
        }

        //Method: Populate the DropDownList of Places 
        private void PopulatePlacesDropDownList(int? selectedPlaceId = null)
        {
            if (selectedPlaceId == null)
            {
                var places = _unitOfWork.PlaceRepository.GetList().OrderBy(o => o.NamePlace);
                ViewBag.PlaceIdSt = new SelectList(places, "PlaceId", "NamePlace");
            }
            else
            {
                var places = _unitOfWork.PlaceRepository.GetList().OrderBy(o => o.NamePlace);
                ViewBag.PlaceIdSt = new SelectList(places, "PlaceId", "NamePlace", selectedPlaceId);
            }
        }

        //Method: Populate the DropDownList of Cities 
        private void PopulateCitiesDropDownList(int? selectedCityId = null)
        {
            if (selectedCityId == null)
            {
                var cities = _unitOfWork.CityRepository.GetList().OrderBy(o => o.CityName);
                ViewBag.CityIdSt = new SelectList(cities, "CityId", "CityName");
            }
            else
            {
                var cities = _unitOfWork.CityRepository.GetList().OrderBy(o => o.CityName);
                ViewBag.CityIdSt = new SelectList(cities, "CityId", "CityName", selectedCityId);
            }
        }

        //Method: Build Statistical Data Chart
        private string BuildStatisticChart(IEnumerable<Statistic> sd)
        {
            //_infoMessage = false;

            var strGoogleChart = new StringBuilder();
            
            strGoogleChart.Append("<script type=*text/javascript* src=*https://www.google.com/jsapi*></script>" +
                      "<script type=*text/javascript*>" +
                      "google.load( *visualization*, *1*, {packages:[*corechart*]});" +
                      "google.setOnLoadCallback(drawChart); drawChart();" +
                      "function drawChart() {" +
                      "var data = new google.visualization.DataTable();" +
                      "data.addColumn('string', 'Dado');" +
                      "data.addColumn('number', 'Valor');" +
                      "data.addColumn({type: 'string', role: 'annotation'});");

            // Adiciona Parâmetros para visualizar no gráfico
            //strGoogleChart.Append("data.addColumn('number', 'Valor');");


			// Adicionar dados para o(s) respetivo(s) parâmetros => ex: data.addRows([[p1,p2],[p1,p2],...])
            strGoogleChart.Append("data.addRows([");

            var statistics = sd as IList<Statistic> ?? sd.OrderBy(c => c.DataName).ToList();
            var numLines = statistics.Count();
            int i = 0;

            
            foreach (var ln in statistics)
            {
                i++;
                strGoogleChart.Append("[");

                strGoogleChart.Append("'" + ln.DataName + "'," + ln.DataCount + ",'" + ln.DataCount + "'");

                strGoogleChart.Append(i < numLines ? "]," : "]");
            }
           
			
			//fecha ciclo
			
            strGoogleChart.Append("]);");
			
            strGoogleChart.Append("var options = {" +
                    "title: ''," +
                    //"width: '955'," +
                    //"height: 370,"+
                    "legend: 'none'," +
                    "chartArea: {left:'8%', top:'10%', width:'100%', height:'50%' }, " +
                    "vAxis: { title: 'N.º de Eventos' }," +
                    "hAxis: { title: '', slantedText : 'true', slantedTextAngle: 60 }," +
                    //"axisTitlesPosition: 'in', " + 
                    //"series: { 0:{ LabelWidth: 200} }, " + 
                    "explorer: { axis: 'horizontal', keepInBounds: 'true'}," +
                    "color: 'blue' };" +
                    "var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));" +
                    "options.chtt = 'Congressional Scorecard';" +
                    "chart.draw(data, options);}" +
                    "</script>");


            var dadosGrafico = strGoogleChart.ToString().TrimEnd(',').Replace('*', '"');

            return dadosGrafico;

     
        }

    }  //End Controller  
}